package org.opencv.samples.facedetect;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;

import org.opencv.android.BaseLoaderCallback;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewFrame;
import org.opencv.android.LoaderCallbackInterface;
import org.opencv.android.OpenCVLoader;
import org.opencv.core.Core;
import org.opencv.core.Mat;
import org.opencv.core.MatOfRect;
import org.opencv.core.Rect;
import org.opencv.core.Scalar;
import org.opencv.core.Size;
import org.opencv.android.CameraBridgeViewBase;
import org.opencv.android.CameraBridgeViewBase.CvCameraViewListener2;
import org.opencv.objdetect.CascadeClassifier;
import org.opencv.samples.facedetect.R.id;

import android.R.string;
import android.annotation.SuppressLint;
import android.app.Activity;
import android.content.Context;
import android.graphics.Color;
import android.hardware.Camera;
import android.hardware.Camera.Parameters;
import android.os.Bundle;
import android.os.Handler;
import android.util.Log;
import android.view.Menu;
import android.view.MenuItem;
import android.view.WindowManager;
//import android.view.View;
import android.view.TextureView;
import android.widget.Button;
import android.widget.FrameLayout.LayoutParams;
import android.widget.LinearLayout;
import android.widget.RelativeLayout;
import android.widget.TextView;

public class FdActivity extends Activity implements CvCameraViewListener2 {

    private static final String    TAG                 = "OCVSample::Activity";
    private static final Scalar    FACE_RECT_COLOR     = new Scalar(0, 255, 0, 255);
    public static final int        JAVA_DETECTOR       = 0;
    public static final int        NATIVE_DETECTOR     = 1;

    private MenuItem               mItemFace50;
    private MenuItem               mItemFace40;
    private MenuItem               mItemFace30;
    private MenuItem               mItemFace20;
    private MenuItem               mItemType;

    private Mat                    mRgba;
    private Mat                    mGray;
    private File                   mCascadeFile;
    private CascadeClassifier      mJavaDetector;
    private DetectionBasedTracker  mNativeDetector;

    private int                    mDetectorType       = JAVA_DETECTOR;
    private String[]               mDetectorName;

    private float                  mRelativeFaceSize   = 0.2f;
    private int                    mAbsoluteFaceSize   = 0;

//	private TextView matching_method;
	private static final int MY_BUTTON = 9000;
	
    private CameraBridgeViewBase   mOpenCvCameraView;
    private TextView tv1, tv2;
    int y_now=0, y_old1 = 0, y_old2 = 0, ymin = 0, ymin_old = 0, ymax = 0, ymax_old = 0, xxx = 0;
    boolean y_max_true = false, y_min_true=false;
    private Camera camera = null;
 // Handler gets created on the UI-thread
    //private Handler mHandler = new Handler();
    
   private BaseLoaderCallback  mLoaderCallback = new BaseLoaderCallback(this) {
        @SuppressLint("NewApi")
		@Override
        public void onManagerConnected(int status) {
            switch (status) {
                case LoaderCallbackInterface.SUCCESS:
                {
                    Log.i(TAG, "OpenCV loaded successfully");

                    // Load native library after(!) OpenCV initialization
                    System.loadLibrary("detection_based_tracker");

                    try {
                        // load cascade file from application resources
                    	
                  //  	if (getResources().getConfiguration().orientation != Configuration.ORIENTATION_LANDSCAPE) {
                  //          camera.setDisplayOrientation(90);
                  //          lp.height = previewSurfaceHeight;
                  //          lp.width = (int) (previewSurfaceHeight / aspect);
                  //      } 
                    	
                        InputStream is = getResources().openRawResource(R.raw.lbpcascade_frontalface);
                        File cascadeDir = getDir("cascade", Context.MODE_PRIVATE);
                        mCascadeFile = new File(cascadeDir, "lbpcascade_frontalface.xml");
                        FileOutputStream os = new FileOutputStream(mCascadeFile);

                        byte[] buffer = new byte[4096];
                        int bytesRead;
                        while ((bytesRead = is.read(buffer)) != -1) {
                            os.write(buffer, 0, bytesRead);
                        }
                        is.close();
                        os.close();

                        mJavaDetector = new CascadeClassifier(mCascadeFile.getAbsolutePath());
                        if (mJavaDetector.empty()) {
                            Log.e(TAG, "Failed to load cascade classifier");
                            mJavaDetector = null;
                        } else
                            Log.i(TAG, "Loaded cascade classifier from " + mCascadeFile.getAbsolutePath());

                        mNativeDetector = new DetectionBasedTracker(mCascadeFile.getAbsolutePath(), 0);

                        cascadeDir.delete();

                    } catch (IOException e) {
                        e.printStackTrace();
                        Log.e(TAG, "Failed to load cascade. Exception thrown: " + e);
                    }

              
		//	@SuppressWarnings("unused")
		//	Parameters parameters = camera.getParameters();
           //         parameters.setRotation(90);
               //     mOpenCvCameraView.getRotation();
                    
            //        mOpenCvCameraView.setr.setRotation(30);
                    //mOpenCvCameraView.setRotationX(90);
                    mOpenCvCameraView.enableView();
                } break;
                default:
                {
                    super.onManagerConnected(status);
                } break;
            }
        }
    };

    public FdActivity() {
        mDetectorName = new String[2];
        mDetectorName[JAVA_DETECTOR] = "Java";
        mDetectorName[NATIVE_DETECTOR] = "Native (tracking)";

        Log.i(TAG, "Instantiated new " + this.getClass());
    }

    /** Called when the activity is first created. */
    @Override
    public void onCreate(Bundle savedInstanceState) {
        Log.i(TAG, "called onCreate");
        super.onCreate(savedInstanceState);
        getWindow().addFlags(WindowManager.LayoutParams.FLAG_KEEP_SCREEN_ON);    
       
        setContentView(R.layout.face_detect_surface_view);
        
        mOpenCvCameraView = (CameraBridgeViewBase) findViewById(R.id.fd_activity_surface_view);
        mOpenCvCameraView.setCvCameraViewListener(this);
       
        
    }

    @Override
    public void onPause()
    {
        super.onPause();
        if (mOpenCvCameraView != null)
            mOpenCvCameraView.disableView();
    }

    @Override
    public void onResume()
    {
        super.onResume();
        OpenCVLoader.initAsync(OpenCVLoader.OPENCV_VERSION_2_4_3, this, mLoaderCallback);
    }

    public void onDestroy() {
        super.onDestroy();
        mOpenCvCameraView.disableView();
    }

    public void onCameraViewStarted(int width, int height) {
        mGray = new Mat();
        mRgba = new Mat();
    }

    public void onCameraViewStopped() {
        mGray.release();
        mRgba.release();
    }

    public Mat onCameraFrame(CvCameraViewFrame inputFrame) {

        mRgba = inputFrame.rgba();
        mGray = inputFrame.gray();

        if (mAbsoluteFaceSize == 0) {
            int height = mGray.rows();
            if (Math.round(height * mRelativeFaceSize) > 0) {
                mAbsoluteFaceSize = Math.round(height * mRelativeFaceSize);
            }
            mNativeDetector.setMinFaceSize(mAbsoluteFaceSize);
        }

        MatOfRect faces = new MatOfRect();

        if (mDetectorType == JAVA_DETECTOR) {
            if (mJavaDetector != null)
                mJavaDetector.detectMultiScale(mGray, faces, 1.1, 2, 2, // TODO: objdetect.CV_HAAR_SCALE_IMAGE
                        new Size(mAbsoluteFaceSize, mAbsoluteFaceSize), new Size());
        }
        else if (mDetectorType == NATIVE_DETECTOR) {
            if (mNativeDetector != null)
                mNativeDetector.detect(mGray, faces);
        }
        else {
            Log.e(TAG, "Detection method is not selected!");
        }

      
        
        Rect[] facesArray = faces.toArray();
        Log.e(TAG, "faceArray length: " + facesArray.length);

    
        if (facesArray.length != 0) {
        	Log.e(TAG, "x: " + facesArray[0].x + "   y: " + facesArray[0].y);
        	CoordinatesView(facesArray[0].x, facesArray[0].y);
        	
          	Core.rectangle(mRgba, facesArray[0].tl(), facesArray[0].br(), FACE_RECT_COLOR, 3);   
          	
          	y_now = facesArray[0].y;
          	
       	    
          	if ((y_now - y_old1) == 0){

          	}      	         	
          	if ((y_now - y_old1) > 0){
          		if(((y_old2 - y_old1) < 0) && (y_now - y_old1) > 0){
          			y_min_true = true;	
          		} 
          		y_old2 = y_old1;
          		y_old1 = y_now;
          		ymax = y_now; 
          	}
          	if ((y_now - y_old1) < 0){
          		if(((y_old2 - y_old1) > 0) && (y_now - y_old1) < 0){
          			y_max_true = true;	
          		} 
          		y_old1 = y_now;
          		ymin = y_now;
          	}       	
          	
          	xxx = xxx + 1;
          	
        	Log.e(TAG, "y_min_true: " + y_min_true);
        	Log.e(TAG, "y_max_true: " + y_max_true);
        	Log.e(TAG, "y_now - y_old1: " + (y_now - y_old1));
        	Log.e(TAG, "xxx: " + xxx);
          	
          	if ((y_max_true == true) && (y_min_true == true)){
          		SpeedView(xxx);
          		y_max_true = false;
          	    y_min_true = false;
          	    xxx = 0;
            	Log.e(TAG, "Yessss!!!!");
          	}
        }
        
        if (facesArray.length == 0){
            int aaa = 0;
            SpeedView(aaa);
        	CoordinatesView(aaa, aaa);
        }
      
       return mRgba;
    }
    
    public void CoordinatesView(final int x, final int y) {
        runOnUiThread(new Runnable() {
            public void run() {
                // use data here
            //    data.doSomething();
            tv1 = (TextView)findViewById(R.id.textView1);
           	tv1.setText("   x: " + x + "   y: " + y);
            }
        });
    }
    
    public void SpeedView(final int v) {
        runOnUiThread(new Runnable() {
            public void run() {
                // use data here
            //    data.doSomething();
            tv2 = (TextView)findViewById(R.id.textView2);
           	tv2.setText("   Speed: " + v);
            }
        });
    }
    
    
    @Override
    public boolean onCreateOptionsMenu(Menu menu) {
        Log.i(TAG, "called onCreateOptionsMenu");
        mItemFace50 = menu.add("Face size 50%");
        mItemFace40 = menu.add("Face size 40%");
        mItemFace30 = menu.add("Face size 30%");
        mItemFace20 = menu.add("Face size 20%");
        mItemType   = menu.add(mDetectorName[mDetectorType]);
        return true;
    }

    @Override
    public boolean onOptionsItemSelected(MenuItem item) {
        Log.i(TAG, "called onOptionsItemSelected; selected item: " + item);
        if (item == mItemFace50)
            setMinFaceSize(0.5f);
        else if (item == mItemFace40)
            setMinFaceSize(0.4f);
        else if (item == mItemFace30)
            setMinFaceSize(0.3f);
        else if (item == mItemFace20)
            setMinFaceSize(0.2f);
        else if (item == mItemType) {
            mDetectorType = (mDetectorType + 1) % mDetectorName.length;
            item.setTitle(mDetectorName[mDetectorType]);
            setDetectorType(mDetectorType);
        }
        return true;
    }

    private void setMinFaceSize(float faceSize) {
        mRelativeFaceSize = faceSize;
        mAbsoluteFaceSize = 0;
    }

    private void setDetectorType(int type) {
        if (mDetectorType != type) {
            mDetectorType = type;

            if (type == NATIVE_DETECTOR) {
                Log.i(TAG, "Detection Based Tracker enabled");
                mNativeDetector.start();
            } else {
                Log.i(TAG, "Cascade detector enabled");
                mNativeDetector.stop();
            }
        }
    }
}
